package team.stride.database;

import java.util.HashMap;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;

public class StrideDB extends ContentProvider
{
	public static final String AUTHORITY = "team.stride.database.StrideDB";
	private static final String DATABASE_NAME = "stride.db";
	private static final int DATABASE_VERSION = 7;

	// table RESULTS
	public static final String TABLE_NAME_RESULTS = "results";
	public static final String CONTENT_TYPE_RESULTS = "results";
	public static final String ID_R = "ID";
	public static final String NAME_R = "NAME";
	public static final String USERNAME_R = "USERNAME";
	public static final String TRACKNAME_R = "TRACKNAME";
	public static final String TIME_R = "TIME";
	public static final String DATE_R = "DATE";
	public static final String LENGTH_R = "LENGTH";
	public static final String TOPSPEED_R = "TOPSPEED";
	public static final String LAPS_R = "LAPS";
	public static final String DETAILS_R = "DETAILS";

	// table tracks
	public static final String TABLE_NAME_TRACKS = "tracks";
	public static final String CONTENT_TYPE_TRACKS = "tracks";
	public static final String ID_T = "ID";
	public static final String NAME_T = "NAME";
	public static final String LENGTH_T = "LENGTH";
	public static final String GPX_T = "GPX";
	public static final String DETAILS_T = "DETAILS";

	// table users
	public static final String TABLE_NAME_USERS = "users";
	public static final String CONTENT_TYPE_USERS = "users";
	public static final String ID_U = "ID";
	public static final String NAME_U = "NAME";
	public static final String PLAYLIST_U = "PLAYLIST";
	public static final String NETWORK_U = "NETWORK";
	public static final String DETAILS_U = "DETAILS";

	// table IMPORTS
	public static final String TABLE_NAME_IMPORTS = "imports";
	public static final String CONTENT_TYPE_IMPORTS = "imports";
	public static final String ID_I = "ID";
	public static final String NAME_I = "NAME";
	public static final String USERNAME_I = "USERNAME";
	public static final String TIME_I = "TIME";
	public static final String DATE_I = "DATE";
	public static final String LENGTH_I = "LENGTH";
	public static final String TOPSPEED_I = "TOPSPEED";
	public static final String DETAILS_I = "DETAILS";

	// table playlists
	public static final String TABLE_NAME_PLAYLISTS = "playlists";
	public static final String CONTENT_TYPE_PLAYLISTS = "playlists";
	public static final String ID_P = "ID";
	public static final String NAME_P = "NAME";
	public static final String DETAILS_P = "DETAILS";

	// table music
	public static final String TABLE_NAME_MUSIC = "music";
	public static final String CONTENT_TYPE_MUSIC = "music";
	public static final String ID_M = "ID";
	public static final String SONG_M = "SONG";
	public static final String SINGER_M = "SINGER";
	public static final String PLAYLIST_M = "PLAYLIST";
	public static final String FILE_M = "FILE";
	public static final String DETAILS_M = "DETAILS";

	public static final Uri CONTENT_URI_RESULTS = Uri.parse("content://" + AUTHORITY + "/" + TABLE_NAME_RESULTS);
	public static final Uri CONTENT_URI_TRACKS = Uri.parse("content://" + AUTHORITY + "/" + TABLE_NAME_TRACKS);
	public static final Uri CONTENT_URI_USERS = Uri.parse("content://" + AUTHORITY + "/" + TABLE_NAME_USERS);
	public static final Uri CONTENT_URI_IMPORTS = Uri.parse("content://" + AUTHORITY + "/" + TABLE_NAME_IMPORTS);
	public static final Uri CONTENT_URI_PLAYLISTS = Uri.parse("content://" + AUTHORITY + "/" + TABLE_NAME_PLAYLISTS);
	public static final Uri CONTENT_URI_MUSIC = Uri.parse("content://" + AUTHORITY + "/" + TABLE_NAME_MUSIC);

	private static HashMap<String, String> resultsProjectionMap;
	private static HashMap<String, String> tracksProjectionMap;
	private static HashMap<String, String> usersProjectionMap;
	private static HashMap<String, String> importsProjectionMap;
	private static HashMap<String, String> playlistsProjectionMap;
	private static HashMap<String, String> musicProjectionMap;

	public static final int MATCH_R = 1;
	public static final int MATCH_T = 2;
	public static final int MATCH_U = 3;
	public static final int MATCH_I = 4;
	public static final int MATCH_P = 5;
	public static final int MATCH_M = 6;

	private static final UriMatcher sUriMatcher;

	private static class DatabaseHelper extends SQLiteOpenHelper
	{
		DatabaseHelper(Context context)
		{
			super(context, DATABASE_NAME, null, DATABASE_VERSION);
		}

		@Override
		public void onCreate(SQLiteDatabase db)
		{
			db.execSQL("CREATE TABLE " + TABLE_NAME_RESULTS + " (" + ID_R + " INTEGER PRIMARY KEY AUTOINCREMENT,"
					+ NAME_R + " TEXT," + USERNAME_R + " TEXT," + TRACKNAME_R + " TEXT," + TIME_R + " INTEGER, "
					+ TOPSPEED_R + " NUMBER, " + LENGTH_R + " NUMBER, " + DATE_R + " INTEGER, " + LAPS_R + " NUMBER, "
					+ DETAILS_R + " TEXT);");

			db.execSQL("CREATE TABLE " + TABLE_NAME_TRACKS + " (" + ID_T + " INTEGER PRIMARY KEY AUTOINCREMENT,"
					+ NAME_T + " TEXT," + LENGTH_T + " INTEGER," + GPX_T + " TEXT," + DETAILS_T + " TEXT);");

			db.execSQL("CREATE TABLE " + TABLE_NAME_USERS + " (" + ID_U + " INTEGER PRIMARY KEY AUTOINCREMENT,"
					+ NAME_U + " TEXT," + NETWORK_U + " TEXT," + PLAYLIST_U  + " TEXT," + DETAILS_U + " TEXT);");

			db.execSQL("CREATE TABLE " + TABLE_NAME_IMPORTS + " (" + ID_I + " INTEGER PRIMARY KEY AUTOINCREMENT,"
					+ NAME_I + " TEXT," + USERNAME_I + " TEXT," + TIME_I + " INTEGER, " + TOPSPEED_I + " NUMBER, "
					+ LENGTH_I + " NUMBER, " + DATE_I + " TEXT, " + DETAILS_I + " TEXT);");

			db.execSQL("CREATE TABLE " + TABLE_NAME_PLAYLISTS + " (" + ID_P + " INTEGER PRIMARY KEY AUTOINCREMENT,"
					+ NAME_P + " TEXT," + DETAILS_P + " TEXT);");

			db.execSQL("CREATE TABLE " + TABLE_NAME_MUSIC + " (" + ID_M + " INTEGER PRIMARY KEY AUTOINCREMENT,"
					+ SONG_M + " TEXT," + SINGER_M + " TEXT," + PLAYLIST_M + " TEXT, " + FILE_M + " TEXT, " + DETAILS_M
					+ " TEXT);");
		}

		@Override
		public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
		{
			db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME_RESULTS);
			db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME_TRACKS);
			db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME_USERS);
			db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME_IMPORTS);
			db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME_PLAYLISTS);
			db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME_MUSIC);
			onCreate(db);
		}
	}

	static
	{
		sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

		resultsProjectionMap = new HashMap<String, String>();
		sUriMatcher.addURI(AUTHORITY, TABLE_NAME_RESULTS, MATCH_R);
		resultsProjectionMap.put(ID_R, ID_R);
		resultsProjectionMap.put(NAME_R, NAME_R);
		resultsProjectionMap.put(USERNAME_R, USERNAME_R);
		resultsProjectionMap.put(TOPSPEED_R, TOPSPEED_R);
		resultsProjectionMap.put(LENGTH_R, LENGTH_R);
		resultsProjectionMap.put(TRACKNAME_R, TRACKNAME_R);
		resultsProjectionMap.put(TIME_R, TIME_R);
		resultsProjectionMap.put(DATE_R, DATE_R);
		resultsProjectionMap.put(LAPS_R, LAPS_R);
		resultsProjectionMap.put(DETAILS_R, DETAILS_R);

		tracksProjectionMap = new HashMap<String, String>();
		sUriMatcher.addURI(AUTHORITY, TABLE_NAME_TRACKS, MATCH_T);
		tracksProjectionMap.put(ID_T, ID_T);
		tracksProjectionMap.put(NAME_T, NAME_T);
		tracksProjectionMap.put(LENGTH_T, LENGTH_T);
		tracksProjectionMap.put(GPX_T, GPX_T);
		tracksProjectionMap.put(DETAILS_T, DETAILS_T);

		usersProjectionMap = new HashMap<String, String>();
		sUriMatcher.addURI(AUTHORITY, TABLE_NAME_USERS, MATCH_U);
		usersProjectionMap.put(ID_U, ID_U);
		usersProjectionMap.put(NAME_U, NAME_U);
		usersProjectionMap.put(PLAYLIST_M, PLAYLIST_U);
		usersProjectionMap.put(NETWORK_U, NETWORK_U);
		usersProjectionMap.put(DETAILS_U, DETAILS_U);

		importsProjectionMap = new HashMap<String, String>();
		sUriMatcher.addURI(AUTHORITY, TABLE_NAME_IMPORTS, MATCH_I);
		importsProjectionMap.put(ID_I, ID_I);
		importsProjectionMap.put(NAME_I, NAME_I);
		importsProjectionMap.put(USERNAME_I, USERNAME_I);
		importsProjectionMap.put(TOPSPEED_I, TOPSPEED_I);
		importsProjectionMap.put(LENGTH_I, LENGTH_I);
		importsProjectionMap.put(TIME_I, TIME_I);
		importsProjectionMap.put(DATE_I, DATE_I);
		importsProjectionMap.put(DETAILS_I, DETAILS_I);

		playlistsProjectionMap = new HashMap<String, String>();
		sUriMatcher.addURI(AUTHORITY, TABLE_NAME_PLAYLISTS, MATCH_P);
		playlistsProjectionMap.put(ID_P, ID_P);
		playlistsProjectionMap.put(NAME_P, NAME_P);
		playlistsProjectionMap.put(DETAILS_P, DETAILS_P);

		musicProjectionMap = new HashMap<String, String>();
		sUriMatcher.addURI(AUTHORITY, TABLE_NAME_MUSIC, MATCH_M);
		musicProjectionMap.put(ID_M, ID_M);
		musicProjectionMap.put(SONG_M, SONG_M);
		musicProjectionMap.put(SINGER_M, SINGER_M);
		musicProjectionMap.put(PLAYLIST_M, PLAYLIST_M);
		musicProjectionMap.put(FILE_M, FILE_M);
		musicProjectionMap.put(DETAILS_M, DETAILS_M);
	}

	private DatabaseHelper dbHelper;

	@Override
	public int delete(Uri uri, String where, String[] whereArgs)
	{
		final SQLiteDatabase db = dbHelper.getWritableDatabase();
		int count;
		switch (sUriMatcher.match(uri))
		{
		case MATCH_R:
			count = db.delete(TABLE_NAME_RESULTS, where, whereArgs);
			break;
		case MATCH_T:
			count = db.delete(TABLE_NAME_TRACKS, where, whereArgs);
			break;
		case MATCH_U:
			count = db.delete(TABLE_NAME_USERS, where, whereArgs);
			break;
		case MATCH_I:
			count = db.delete(TABLE_NAME_IMPORTS, where, whereArgs);
			break;
		case MATCH_P:
			count = db.delete(TABLE_NAME_PLAYLISTS, where, whereArgs);
			break;
		case MATCH_M:
			count = db.delete(TABLE_NAME_MUSIC, where, whereArgs);
			break;
		default:
			throw new IllegalArgumentException("Unknown URI " + uri);
		}

		getContext().getContentResolver().notifyChange(uri, null);
		return count;
	}

	@Override
	public String getType(Uri uri)
	{
		switch (sUriMatcher.match(uri))
		{
		case MATCH_R:
			return CONTENT_TYPE_RESULTS;
		case MATCH_T:
			return CONTENT_TYPE_TRACKS;
		case MATCH_U:
			return CONTENT_TYPE_USERS;
		case MATCH_I:
			return CONTENT_TYPE_IMPORTS;
		case MATCH_P:
			return CONTENT_TYPE_PLAYLISTS;
		case MATCH_M:
			return CONTENT_TYPE_MUSIC;
		default:
			throw new IllegalArgumentException("Unknown URI " + uri);
		}
	}

	@Override
	public Uri insert(Uri uri, ContentValues initialValues)
	{
		ContentValues values;

		if (initialValues != null)
		{
			values = new ContentValues(initialValues);
		}
		else
		{
			values = new ContentValues();
		}
		final SQLiteDatabase db = dbHelper.getWritableDatabase();
		long rowId;
		switch (sUriMatcher.match(uri))
		{
		case MATCH_R:
			rowId = db.insert(TABLE_NAME_RESULTS, ID_R, values);
			if (rowId > 0)
			{
				final Uri noteUri = ContentUris.withAppendedId(CONTENT_URI_RESULTS, rowId);
				getContext().getContentResolver().notifyChange(noteUri, null);
				return noteUri;
			}
		case MATCH_T:
			rowId = db.insert(TABLE_NAME_TRACKS, ID_T, values);
			if (rowId > 0)
			{
				final Uri noteUri = ContentUris.withAppendedId(CONTENT_URI_TRACKS, rowId);
				getContext().getContentResolver().notifyChange(noteUri, null);
				return noteUri;
			}
			break;
		case MATCH_U:
			rowId = db.insert(TABLE_NAME_USERS, ID_U, values);
			if (rowId > 0)
			{
				final Uri noteUri = ContentUris.withAppendedId(CONTENT_URI_USERS, rowId);
				getContext().getContentResolver().notifyChange(noteUri, null);
				return noteUri;
			}
			break;
		case MATCH_I:
			rowId = db.insert(TABLE_NAME_IMPORTS, ID_I, values);
			if (rowId > 0)
			{
				final Uri noteUri = ContentUris.withAppendedId(CONTENT_URI_IMPORTS, rowId);
				getContext().getContentResolver().notifyChange(noteUri, null);
				return noteUri;
			}
			break;
		case MATCH_P:
			rowId = db.insert(TABLE_NAME_PLAYLISTS, ID_P, values);
			if (rowId > 0)
			{
				final Uri noteUri = ContentUris.withAppendedId(CONTENT_URI_PLAYLISTS, rowId);
				getContext().getContentResolver().notifyChange(noteUri, null);
				return noteUri;
			}
			break;
		case MATCH_M:
			rowId = db.insert(TABLE_NAME_MUSIC, ID_M, values);
			if (rowId > 0)
			{
				final Uri noteUri = ContentUris.withAppendedId(CONTENT_URI_MUSIC, rowId);
				getContext().getContentResolver().notifyChange(noteUri, null);
				return noteUri;
			}
			break;
		default:
			throw new IllegalArgumentException("Unknown URI " + uri);
		}

		throw new SQLException("Failed to insert row into " + uri);
	}

	@Override
	public boolean onCreate()
	{
		dbHelper = new DatabaseHelper(getContext());
		return true;
	}

	@Override
	public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
	{
		final SQLiteQueryBuilder qb = new SQLiteQueryBuilder();

		switch (sUriMatcher.match(uri))
		{
		case MATCH_R:
			qb.setTables(TABLE_NAME_RESULTS);
			qb.setProjectionMap(resultsProjectionMap);
			break;
		case MATCH_T:
			qb.setTables(TABLE_NAME_TRACKS);
			qb.setProjectionMap(tracksProjectionMap);
			break;
		case MATCH_U:
			qb.setTables(TABLE_NAME_USERS);
			qb.setProjectionMap(usersProjectionMap);
			break;
		case MATCH_I:
			qb.setTables(TABLE_NAME_IMPORTS);
			qb.setProjectionMap(importsProjectionMap);
			break;
		case MATCH_P:
			qb.setTables(TABLE_NAME_PLAYLISTS);
			qb.setProjectionMap(playlistsProjectionMap);
			break;
		case MATCH_M:
			qb.setTables(TABLE_NAME_MUSIC);
			qb.setProjectionMap(musicProjectionMap);
			break;
		default:
			throw new IllegalArgumentException("Unknown URI " + uri);
		}

		final SQLiteDatabase db = dbHelper.getReadableDatabase();
		final Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, sortOrder);

		c.setNotificationUri(getContext().getContentResolver(), uri);
		return c;
	}

	@Override
	public int update(Uri uri, ContentValues values, String where, String[] whereArgs)
	{
		final SQLiteDatabase db = dbHelper.getWritableDatabase();
		int count;
		switch (sUriMatcher.match(uri))
		{
		case MATCH_R:
			count = db.update(TABLE_NAME_RESULTS, values, where, whereArgs);
			break;
		case MATCH_T:
			count = db.update(TABLE_NAME_TRACKS, values, where, whereArgs);
			break;
		case MATCH_U:
			count = db.update(TABLE_NAME_USERS, values, where, whereArgs);
			break;
		case MATCH_I:
			count = db.update(TABLE_NAME_IMPORTS, values, where, whereArgs);
			break;
		case MATCH_P:
			count = db.update(TABLE_NAME_PLAYLISTS, values, where, whereArgs);
			break;
		case MATCH_M:
			count = db.update(TABLE_NAME_MUSIC, values, where, whereArgs);
			break;
		default:
			throw new IllegalArgumentException("Unknown URI " + uri);
		}

		getContext().getContentResolver().notifyChange(uri, null);
		return count;
	}
}

